package com.shenmazong.servertalkzuul.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.netflix.zuul.http.HttpServletRequestWrapper;
import com.shenmazong.utils.JwtTokenUtils;
import com.shenmazong.utils.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 田不平
 * @project demo-easytalk
 * @date 2020/9/15 4:10 PM
 * http://www.shenmazong.com
 */

@Component
@Slf4j
public class LoginZuulFilter extends ZuulFilter {

    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 四种类型：pre,routing,error,post
     * pre：主要用在路由映射的阶段是寻找路由映射表的
     * routing:具体的路由转发过滤器是在routing路由器，具体的请求转发的时候会调用
     * error:一旦前面的过滤器出错了，会调用error过滤器。
     * post:当routing，error运行完后才会调用该过滤器，是在最后阶段的
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 自定义过滤器执行的顺序，数值越大越靠后执行，越小就越先执行
     * @return
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 控制过滤器生效不生效，可以在里面写一串逻辑来控制
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 执行过滤逻辑
     * @return
     */
    @Override
    public Object run() throws ZuulException {

        System.out.println("Zuul 进入网关过滤器...");
        RequestContext currentContext = RequestContext.getCurrentContext();
        currentContext.getResponse().setContentType("text/html;charset=UTF-8");
        HttpServletRequest request = currentContext.getRequest();

        //--0
        String uri = request.getRequestURI();
        if(uri.contains("/login/")) {
            log.info("放过：login:"+uri);
            return null;
        }

        //--1 获取token
//        String token = request.getHeader("token");
        String token = request.getParameter("token");

//        String token = (String)currentContext.get("token");
//        System.out.println(token);

//        HttpServletRequestWrapper httpServletRequestWrapper = (HttpServletRequestWrapper) request;
//        token = httpServletRequestWrapper.getRequest().getParameter("token");

        //--2 验证token
//        if (StringUtils.isEmpty(token)){
//            log.info("阻止：没有token:"+uri);
//            return doFailedResult(currentContext);
//        }
//
//        //--3 验证token有效性
//        HashMap resultMap = JwtTokenUtils.verifyToken(token);
//        if(resultMap.size() <= 0) {
//            log.info("阻止：token无效:"+uri);
//            return doFailedResult(currentContext);
//        }
//
//        //--4 进行redis验证
//        String roles = (String)resultMap.get("roles");
//        String userId = (String)resultMap.get("userId");
//
//        String key = roles + "_token_" + userId;
//        String redisToken = (String)redisTemplate.opsForValue().get(key);
//        if(redisToken == null) {
//            log.info("阻止：token过期:"+uri);
//            return doFailedResult(currentContext);
//        }
//        if(!token.equals(redisToken)) {
//            log.info("阻止：token错误:"+uri);
//            return doFailedResult(currentContext);
//        }

        //--5 终于成功了
        return null;
    }

    /**
     * TODO doFailedResult 失败返回
     * @return
     */
    private Object doFailedResult(RequestContext ctx) {
        ResponseResult result = ResponseResult.FAIL();
        result.setFailMessage("token失效");

        ObjectMapper mapper = new ObjectMapper();
        String jsonResult = "{code:-1,msg:'未知错误'}";
        try {
            jsonResult = mapper.writerWithDefaultPrettyPrinter()
                    .writeValueAsString(result);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        //不会继续执行....不会去调用服务接口，网关服务直接响应给客户端
        ctx.setSendZuulResponse(false);
        ctx.setResponseBody(jsonResult);
        ctx.setResponseStatusCode(401);
        return null;
    }

}
